package cn.good.payment.controller;

import cn.good.payment.config.AliPayConfig;
import cn.good.payment.servcie.GDOrderService;
import cn.good.pojo.Order;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import springfox.documentation.annotations.ApiIgnore;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@RequestMapping("/doc/aliPay")
@Controller
public class AlipayController {

    private static final Logger logger = LoggerFactory.getLogger(AlipayController.class);
    @Resource
    private AliPayConfig aliPayConfig;
    @Resource
    private AlipayClient alipayClient;
    @Resource
    private GDOrderService gdOrderService;


    /**
     * 向支付宝提交支付请求
     *
     * @param WIDout_trade_no
     *            商户订单号，商户网站订单系统中唯一订单号，必填
     * @param WIDsubject
     *            订单名称，必填
     * @param WIDtotal_amount
     *            付款金额，必填
     */
    @ApiOperation(value = "订单支付", httpMethod = "POST",
            protocols = "HTTP", produces = "application/xml", consumes="application/x-www-form-urlencoded",
            response =  String.class,
            notes = "客户端提交订单支付请求，对该API的返回结果不用处理，浏览器将自动跳转至支付宝。<br><b>请使用普通表单提交，不能使用ajax异步提交。</b>")
    @RequestMapping(value = "/pay", method = RequestMethod.POST,produces="application/xml", consumes="application/x-www-form-urlencoded")
    public void pay(
            @ApiParam(name="WIDout_trade_no",value="订单编号",required=true)
            @RequestParam String WIDout_trade_no,
            @ApiParam(name="WIDsubject",value="订单名称",required=true)
            @RequestParam String WIDsubject,
            @ApiParam(name="WIDtotal_amount",value="订单金额",required=true)
            @RequestParam String WIDtotal_amount, HttpServletResponse response) {

        //构建订单信息
        String productCode="QUICK_WAP_WAY";
        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
        model.setOutTradeNo(WIDout_trade_no);
        model.setSubject(WIDsubject);
        model.setTotalAmount(WIDtotal_amount);
        model.setBody("好大夫在线，" + WIDtotal_amount + "元");
        model.setTimeoutExpress("2m");
        model.setProductCode(productCode);
        //构建请求信息
        AlipayTradeWapPayRequest wapPayRequest =new AlipayTradeWapPayRequest();
        wapPayRequest.setReturnUrl(aliPayConfig.getReturnUrl());
        wapPayRequest.setNotifyUrl(aliPayConfig.getNotifyUrl());
        System.out.println(aliPayConfig.getNotifyUrl());
        wapPayRequest.setBizModel(model);

        //构建
        // 调用SDK生成表单, 并直接将完整的表单html输出到页面
        String form = null;
        try {
            form = alipayClient.pageExecute(wapPayRequest).getBody();
            System.out.println(form);
            response.setContentType("text/html;charset=" + aliPayConfig.getCharset());
            response.getWriter().write(form);
            response.getWriter().flush();
            response.getWriter().close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 导步通知，跟踪支付状态变更
     */
    @ApiIgnore//忽略这个api
    @RequestMapping(value = "/notify", method = RequestMethod.POST)
    public void trackPaymentStatus(HttpServletRequest request,
                                   HttpServletResponse response) throws AlipayApiException, IOException {
        // 一定要验签，防止黑客篡改参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        StringBuilder notifyBuild = new StringBuilder("/****************************** alipay notify ******************************/\n");
        parameterMap.forEach((key, value) -> notifyBuild.append(key + "=" + value[0] + "\n") );
        //log.info(notifyBuild.toString());
        System.out.println("以调用 -----------");
        // https://docs.open.alipay.com/54/106370
        // 获取支付宝POST过来反馈信息
        Map<String,String> params = new HashMap<>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        System.out.println(params);
        boolean flag = AlipaySignature.rsaCheckV1(params,
                aliPayConfig.getAlipayPublicKey(),
                aliPayConfig.getCharset(),
                aliPayConfig.getSignType());
        System.out.println(flag);
        if (flag) {
            /**
             * TODO 需要严格按照如下描述校验通知数据的正确性
             *
             * 商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，
             * 并判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），
             * 同时需要校验通知中的seller_id（或者seller_email) 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email），
             *
             * 上述有任何一个验证不通过，则表明本次通知是异常通知，务必忽略。
             * 在上述验证通过后商户必须根据支付宝不同类型的业务通知，正确的进行不同的业务处理，并且过滤重复的通知结果数据。
             * 在支付宝的业务通知中，只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时，支付宝才会认定为买家付款成功。
             */

            //交易状态
            String tradeStatus = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");
            // 商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no")
                    .getBytes("ISO-8859-1"), "UTF-8");
            // 支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes(
                    "ISO-8859-1"), "UTF-8");
            // TRADE_FINISHED(表示交易已经成功结束，并不能再对该交易做后续操作);
            // TRADE_SUCCESS(表示交易已经成功结束，可以对该交易做后续操作，如：分润、退款等);
            if(tradeStatus.equals("TRADE_FINISHED")){
                //判断该笔订单是否在商户网站中已经做过处理
                //如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，
                // 并判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），并执行商户的业务程序
                //请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
                //如果有做过处理，不执行商户的业务程序
                System.out.println("以调用");
                //注意：
                //如果签约的是可退款协议，退款日期超过可退款期限后（如三个月可退款），支付宝系统发送该交易状态通知
                //如果没有签约可退款协议，那么付款完成后，支付宝系统发送该交易状态通知。
            } else if (tradeStatus.equals("TRADE_SUCCESS")){
                //判断该笔订单是否在商户网站中已经做过处理
                //如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，
                // 并判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），并执行商户的业务程序
                //请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
                //如果有做过处理，不执行商户的业务程序
                logger.info("支付宝回调成功!!!");
                Order order = gdOrderService.searchOrderByNo(out_trade_no);
                if(order.getOrderStatus()!=0){
                    logger.info("订单状态为："+order.getOrderStatus()+"无法处理!");
                    return;
                }
                String total_amount = new String(request.getParameter("total_amount"));
                if(order.getPayAmount().toString().equals(total_amount)){
                    logger.info("订单金额为："+total_amount);
                }
                try {
                    gdOrderService.modifiOrder(out_trade_no,trade_no);
                } catch (Exception e) {
                    e.printStackTrace();
                    logger.info(e.getMessage());
                    return;
                }

                //注意：
                //如果签约的是可退款协议，那么付款完成后，支付宝系统发送该交易状态通知。

            }

            response.getWriter().print("success");
        }
        response.getWriter().print("fail");
    }


    /**
     * 支付宝页面跳转同步通知页面
     */
    @ApiIgnore
    @RequestMapping(value = "/return", method = RequestMethod.GET)
    public void callback(HttpServletRequest request,
                         HttpServletResponse response) throws IOException, AlipayApiException {
        response.setContentType("text/html;charset=" + aliPayConfig.getCharset());
        System.out.println("同步调用！");
        //获取支付宝GET过来反馈信息
        Map<String,String> params = new HashMap<>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        boolean verifyResult = AlipaySignature.rsaCheckV1(params, aliPayConfig.getAlipayPublicKey(), aliPayConfig.getCharset(), aliPayConfig.getSignType());
        if(verifyResult){
            //验证成功
            //请在这里加上商户的业务逻辑程序代码，如保存支付宝交易号
            //商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
            //支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
            System.out.println(params);
            response.sendRedirect("http://www.baidu.com");
        }else{
            System.out.println("验证失败");
        }
    }
}
